using System;
using JetBrains.Annotations;
using UnityEngine;

namespace Actions
{
    public class TargetSelector : MonoBehaviour
    {
        [CanBeNull]
        public GameObject CurrentTarget { get; private set; }
        
        [SerializeField] private TargetSpawner targetSpawner;

        [SerializeField] private LayerMask targetLayerMask;

        private int _aimingPointIndex;
        
        private float _degreePerTarget;
        private Vector2 _degreeBaseline;


        private void Awake()
        {
            _degreePerTarget = 360f / targetSpawner.SpawnPoints.Length;
            
            Quaternion rotation = Quaternion.AngleAxis(-(_degreePerTarget / 2f), Vector3.forward);
            _degreeBaseline = rotation * Vector3.right;
        }

        private void OnEnable()
        {
            PlayerChaser.AnyTargetHitPlayer += PlayerChaser_AnyTargetHitPlayer;
        }
        
        private void OnDisable()
        {
            PlayerChaser.AnyTargetHitPlayer -= PlayerChaser_AnyTargetHitPlayer;
        }

        public void TryMoveCursor(Vector2 input)
        {
            // Debug.Log(input);
            
            float angle = Vector2.SignedAngle(_degreeBaseline, input);
            if (angle < 0f)
            {
                angle = 360f + angle;
            }
        
            int candidateSelectedIndex = CalculateSelectedIndex(angle);
        
            _aimingPointIndex = candidateSelectedIndex;
            UpdateCurrentTarget();
        }
        
        public void UpdateCurrentTarget()
        {
            CurrentTarget = GetTarget(_aimingPointIndex);
        }
        
        private void PlayerChaser_AnyTargetHitPlayer()
        {
            UpdateCurrentTarget();
        }
        
        private int CalculateSelectedIndex(float unsignedDegreeFromBaseline)
        {
            float compareDegree = _degreePerTarget;
            for (int i = 0; i < targetSpawner.SpawnPoints.Length; i++)
            {
                if (unsignedDegreeFromBaseline <= compareDegree)
                {
                    if (GetTarget(i))
                    {
                        return i;
                    }
                    
                    if (GetTarget(GetLoopingAimingIndex(i - 1)))
                    {
                        return GetLoopingAimingIndex(i - 1);
                    }
                    return GetLoopingAimingIndex(i + 1);
                }
                compareDegree += _degreePerTarget;
            }
            return targetSpawner.SpawnPoints.Length - 1;
        }

        private int GetLoopingAimingIndex(int index)
        {
            if (index >= targetSpawner.SpawnPoints.Length)
            {
                index = 0;
            }
            if (index < 0)
            {
                index = targetSpawner.SpawnPoints.Length - 1;
            }
            return index;
        }

        [CanBeNull]
        private GameObject GetTarget(int aimingPointIndex)
        {
            RaycastHit2D hit = Physics2D.Raycast(
                transform.position, 
                targetSpawner.SpawnPoints[aimingPointIndex].position,
                100f,
                targetLayerMask);
            return hit.collider?.gameObject;
        }
    }
}
